﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace Illusion
{
    /// <summary>
    /// Markup extension that retrieves localized resource strings.
    /// </summary>
    [MarkupExtensionReturnType(typeof(string))]
    public sealed class LocalizeExtension : LanguageDependentExtension
    {
        public LocalizeExtension(string key)
        {
            this.key = key;
            this.UpdateOnLanguageChange = true;
        }

        public LocalizeExtension()
        {
            this.UpdateOnLanguageChange = true;
        }

        string key;

        public string Key
        {
            get { return key; }
            set { key = value; }
        }

        public static void ApplyLocalization(DependencyObject obj, DependencyProperty prop, string key)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("The target obj can not be null.");
            }
            if (prop == null)
            {
                throw new ArgumentNullException("The bound prop can not be null.");
            }
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException("The string index key can not be null.");
            }
            obj.SetValueToExtension(prop, new LocalizeExtension(key));
        }

        public override string Value
        {
            get
            {
                return IoC.Get<ResourceService>().GetString(key);
            }
        }
    }

    public abstract class LanguageDependentExtension : MarkupExtension, INotifyPropertyChanged, IWeakEventListener
    {
        protected LanguageDependentExtension()
        {
            this.UpdateOnLanguageChange = true;
        }

        public abstract string Value { get; }

        /// <summary>
        /// Set whether the LocalizeExtension should use a binding to automatically
        /// change the text on language changes.
        /// The default value is true.
        /// </summary>
        public bool UpdateOnLanguageChange { get; set; }

        bool _isRegisteredForLanguageChange;

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (UpdateOnLanguageChange)
            {
                Binding binding = new Binding("Value") { Source = this, Mode = BindingMode.OneWay };
                return binding.ProvideValue(serviceProvider);
            }
            else
            {
                return this.Value;
            }
        }

        [Obsolete("Use ExtensionMethods.SetValueToExtension instead of directly fetching the binding from this extension")]
        public Binding CreateBinding()
        {
            return new Binding("Value") { Source = this, Mode = BindingMode.OneWay };
        }

        event PropertyChangedEventHandler ChangedEvent;

        public event PropertyChangedEventHandler PropertyChanged
        {
            add
            {
                if (!_isRegisteredForLanguageChange)
                {
                    _isRegisteredForLanguageChange = true;
                    LanguageChangeWeakEventManager.AddListener(this);
                }
                ChangedEvent += value;
            }
            remove { ChangedEvent -= value; }
        }

        static readonly PropertyChangedEventArgs
            valueChangedEventArgs = new PropertyChangedEventArgs("Value");

        bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            var handler = ChangedEvent;
            if (handler != null)
                handler(this, valueChangedEventArgs);
            return true;
        }
    }

    public sealed class LanguageChangeWeakEventManager : WeakEventManager
    {
        /// <summary>
        /// Adds a weak event listener.
        /// </summary>
        public static void AddListener(IWeakEventListener listener)
        {
            CurrentManager.ProtectedAddListener(null, listener);
        }

        /// <summary>
        /// Removes a weak event listener.
        /// </summary>
        public static void RemoveListener(IWeakEventListener listener)
        {
            CurrentManager.ProtectedRemoveListener(null, listener);
        }

        /// <summary>
        /// Gets the current manager.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
        private static LanguageChangeWeakEventManager CurrentManager
        {
            get
            {
                LanguageChangeWeakEventManager manager = (LanguageChangeWeakEventManager)GetCurrentManager(typeof(LanguageChangeWeakEventManager));
                if (manager == null)
                {
                    manager = new LanguageChangeWeakEventManager();
                    SetCurrentManager(typeof(LanguageChangeWeakEventManager), manager);
                }
                return manager;
            }
        }

        protected override void StartListening(object source)
        {
            //ResourceService.LanguageChanged += DeliverEvent;
        }

        protected override void StopListening(object source)
        {
            //ResourceService.LanguageChanged -= DeliverEvent;
        }
    }
}
